package spring.aop;


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import spring.beans.factory.BeanFactory;
import spring.beans.factory.DefaultListableBeanFactory;
import spring.utils.ClassLoaderUtil;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * cglib方式实现动态代理
 * Spring提供两种动态代理方法
 * 有接口默认实现jdk原生，没有接口就用cglib
 */
public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {

    private String beanName;
    private Object target;
    private List<Advisor> matchAdvisors;
    private BeanFactory beanFactory;

    public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
        this.beanName = beanName;
        this.target = target;
        this.matchAdvisors = matchAdvisors;
        this.beanFactory = beanFactory;
    }

    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(((DefaultListableBeanFactory)beanFactory).getType(beanName).getClass());
        enhancer.setClassLoader(ClassLoaderUtil.getClassLoader());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        List<MyAdvice> advices = new ArrayList<>();
        for (Advisor advisor : matchAdvisors){
            MyAdvice advice = (MyAdvice) beanFactory.getBean(advisor.getAdviceBeanName());
            advices.add(advice);
        }

        MyChain chain = new MyChain(advices,method,args,target);

        return chain.proceed();
    }
}
